package com.xiu.travel.util;

import org.springframework.util.CollectionUtils;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @version 1.0
 * @date 2021/12/1 5:35 下午
 */
public class TreeUtil
{

    /**
     *
     * @param list 数据
     * @param fun 对应父级的 id
     * @param fun2 标识 父级 的 字段
     * @param <T> 类范型
     * @return 树级结构
     */
    public static <T> List<T> buildTree(List<T> list, Function<T, Long> fun, Function<T, Long> fun2) {
        return buildTree(list, fun, fun2, -1L);
    }

    /**
     *
     * @param list 数据
     * @param fun 对应父级的 id
     * @param fun2 标识 父级 的 字段
     * @param source 最上级parentId 的值
     * @param <T> 类范型
     * @return 树级结构
     */
    public static <T> List<T> buildTree(List<T> list, Function<T, Long> fun, Function<T, Long> fun2, Long source) {
        if (CollectionUtils.isEmpty(list)) {
            return new ArrayList<>(0);
        }
        Map<Long, List<T>> treeMap = list.stream().collect(Collectors.groupingBy(fun2));
        List<T> parents = list.stream().filter(x -> Objects.equals(source, fun2.apply(x))).collect(Collectors.toList());
        return getChildren(parents, fun, treeMap);
    }

    private static <T> List<T> getChildren(List<T> list, Function<T, Long> fun, Map<Long, List<T>> treeMap) {
        for (T x : list) {
            Method setChildren = null;
            try {
                setChildren = x.getClass().getMethod("setChildren", List.class);
            } catch (NoSuchMethodException e) {
                System.out.println("未找到 setChildren 方法");
            }
            if (setChildren != null)
            {
                setChildren.setAccessible(true);
            }
            List<T> ts = treeMap.get(fun.apply(x));
            if (Objects.isNull(ts)) {
                continue;
            }
            try {
                if (setChildren != null)
                {
                    setChildren.invoke(x, getChildren(ts, fun, treeMap));
                }
            } catch (IllegalAccessException | InvocationTargetException e) {
                System.out.println("未知异常");
            }
        }
        return list;
    }
}
